#include <dirent.h>
#include "unp.h"
#include "FtpCommand.h"
#include "FtpState.h"
#include "ClientSocket.h"

#define COMMAND_MAX_SIZE 1024
#define BUFFER_SIZE 1024
#define FILENAME_SIZE 256
#define END_OF_PROTOCOL "\r\n"

void initializeFtpClient();
void startFtpClient(char *startCmd);
void commandHandle(char *cmd);
void defaultHandler(char *cmd);
int modeCheck(const char *option);
void printMessage(char *msg);

void openCon(char *cmd);
void userLog(char *userlogCmd);
void list(char *listCmd);
void nlist(char *nlistCmd);
void getput(char *getCmd);
void put(char *putCmd);
void cd(char *cdCmd);
void quit(char *quitCmd);
void pwd(char *pwdCmd);
void bye(char *byeCmd);
void hash(char *hashCmd);
void passiveMode(char *ip, int *port);
void shellEscape(char *shellCmd);
void syst(char *systCmd);
void close_(char *closeCmd);
void debugOn(char *msg);
void binary(char *binaryCmd);
void ascii(char *asciiCmd);
void passiveOn(char *msg);
void lcd(char *lcdCmd);

void activeMode(); //char* activeCmd);

void checkType(char *typeCmd);

unsigned int downloadFile(int sock, char *filePath, unsigned int fileSize,
		int hashFlag);
unsigned int uploadFile(int sock, char *filePath, int hashFlag);

int connectServer(char *serverIp, short port);

typedef struct _FtpCmdHandler {
	char cmd[5];
	void (*handler)(char* arg);

} FtpCmdHandler;

// Map Ftp Command to Handler
FtpCmdHandler ftpCmdHandler[] = {

{ CMD_OPEN, openCon }, { CMD_USER, userLog }, { CMD_SYST, syst }, { CMD_LIST,
		list }, { CMD_NLIST, nlist }, { CMD_DIR, list }, { CMD_PUT, getput }, {
		CMD_GET, getput }, { CMD_CD, cd }, { CMD_PWD, pwd }, { CMD_HASH, hash },
		{ CMD_CLOSE, close_ }, { CMD_QUIT, quit }, { CMD_BYE, quit }, {
				CMD_SHELL, shellEscape }, { CMD_BINARY, binary }, { CMD_ASCII,
				ascii }, { CMD_DEBUG, debugOn }, { CMD_PASV, passiveOn }, {
				CMD_LCD, lcd }, { CMD_TYPE, checkType }, };

// sock - PI socket ,  dtpSock - DTP socket
int sock, dtpSock, port , listenfd = -1;
char serv_ip[16];
int serv_port;

struct sockaddr_in servaddr, cliaddr;

//char state[COMMAND_MAX_SIZE];
int pasv_mode;
int debug_mode;
int state = 0;
int type;
int hashFlag;
int check_connection=0;
int logstate = 0;
unsigned int fileSize;

char ucmd[COMMAND_MAX_SIZE];

int main(int argc, char const *argv[]) {
	char open_str[25];

	if (argc == 1) {

		checkState();
		//startFtpClient(0);
	} else if (argc == 2) {
		strcpy(open_str, "open ");
		strcat(open_str, argv[1]);
		openCon(open_str);
		checkState();

	} else { //  error
		fprintf(stderr, "\nUsage: %s [ftp server ip]\n", argv[0]);
	}
	return 0;
}

int checkState() {
	// Wait_for_User_CMD
	char cmd[COMMAND_MAX_SIZE];

	while (1) {
		//fprintf(stderr, "CHECK STATE !!!\n");
		switch (state) {
		case STATE_CMD:
			printf("State = Wait_for_User_CMD\n");
			state_Cmd(cmd);
			break;

		case STATE_S:
			printf("State = Wait_for_S_repy\n");
			state_S_reply();
			break;
		case STATE_S1:
			printf("State = Wait_for_S_repy-1\n");
			state_S1_reply(cmd);
			break;
		case STATE_S2:
			printf("State = Wait_for_S_repy-2\n");
			state_S2_reply(cmd);
			break;
		case STATE_S3:
			printf("State = Wait_for_S_repy-3\n");
			state_S3_reply();
			break;
		case STATE_P:
			printf("State = Wait_for_P_reply\n");
			state_P_reply(cmd);
			break;

		case STATE_I:
			printf("State = Wait_for_I_repy\n");
			state_I_reply();
			break;

		case STATE_DT:
			printf("State = Data_Transfer\n");
			state_Data_transfer(cmd);
			break;

		case STATE_EXIT:
			close(sock);
			exit(0);
		}
	}
}

void state_Cmd(char *cmd) {
	int k;

	//initializeFtpClient();

	// input user command

	memset(cmd, 0x00, sizeof(cmd));
	// input user command
	printMessage("ftp>");
	fgets(cmd, COMMAND_MAX_SIZE, stdin);

	k = strlen(cmd);
	*(cmd + (k - 1)) = '\0';

	// call handler
	commandHandle(cmd);

}

void state_S_reply(char* cmd) {
	char sendBuffer[BUFFER_SIZE];
	char recvBuffer[BUFFER_SIZE];
	char reply[5];

	memset(reply, 0x00, sizeof(reply));
	memset(sendBuffer, 0x00, sizeof(sendBuffer));
	memset(recvBuffer, 0x00, sizeof(recvBuffer));

	recvProtocol(sock, recvBuffer, BUFFER_SIZE - 1);
	printMessage(recvBuffer);

	sscanf(recvBuffer, "%s ", reply);

	if (!strcmp(reply, "200")) {
		state = STATE_CMD;
	} else if (!strcmp(reply, "215")) {
		if (logstate == 0) {
			checkType(0);
			logstate = 1;
		}
		state = STATE_CMD;
	} else if (!strcmp(reply, "230")) {
		check_connection = 1; // connection on
		if (logstate == 0) {
			syst(0);
			return;
		}
		state = STATE_CMD;
	} else if (!strcmp(reply, "221")) {
		check_connection = 0;
		close(sock);
		state = STATE_CMD;
	} else if (!strcmp(reply, "250")) {
		state = STATE_CMD;
	} else if (!strcmp(reply, "257")) {
		state = STATE_CMD;
	} else if (!strncmp(reply, "1", 1)) {
		fprintf(stderr, "\nError\n");
		state = STATE_CMD;
	} else if (!strncmp(reply, "3", 1)) {
		fprintf(stderr, "\nError\n");
		state = STATE_CMD;
	} else if (!strncmp(reply, "4", 1) || !strncmp(reply, "5", 1)) {
		fprintf(stderr, "\nLogin failed.\n");
		state = STATE_CMD;
	}
}

void state_S1_reply(char* cmd) {
	char sendBuffer[BUFFER_SIZE];
	char recvBuffer[BUFFER_SIZE];
	char reply[5];
	memset(reply, 0x00, sizeof(reply));
	memset(sendBuffer, 0x00, sizeof(sendBuffer));
	memset(recvBuffer, 0x00, sizeof(recvBuffer));

	recvProtocol(sock, recvBuffer, BUFFER_SIZE - 1);
	printMessage(recvBuffer);

	sscanf(recvBuffer, "%s ", reply);

	if (!strcmp(reply, "200")) {

		if (pasv_mode == PASSIVE) {

			sprintf(sendBuffer, "PASV%s", END_OF_PROTOCOL);
			sendProtocol(sock, sendBuffer);

			state = STATE_S2;

		} else if (pasv_mode == ACTIVE) {

			activeMode();

			state = STATE_S2;
		}

	} else if (!strncmp(reply, "1", 1)) {
		fprintf(stderr, "\nError\n");
		state = STATE_CMD;
	} else if (!strncmp(reply, "3", 1)) {
		fprintf(stderr, "\nError\n");
		state = STATE_CMD;
	} else if (!strncmp(reply, "4", 1) || !strncmp(reply, "5", 1)) {
		fprintf(stderr, "\nFailure\n");
		state = STATE_CMD;
	}

}

// file download
void getput(char *getCmd) {
	char sendBuffer[BUFFER_SIZE];
	char command[BUFFER_SIZE];
	char argument[BUFFER_SIZE];
	char argument2[COMMAND_MAX_SIZE];
	int k;
	memset(command, 0x00, sizeof(command));
	memset(argument, 0x00, sizeof(argument));
	memset(argument2, 0x00, sizeof(argument2));

	if (check_connection == 0) {
		printf("Not connected.\n");
		return;
	}
// get local current working directory

	sscanf(getCmd, "%s %s %s", command, argument2, argument2);

	if (!strcmp(argument, "") && !strcmp(argument2, "")) {

		if (!strcmp(command, "put")) {
			printf("(local-file)\n");
			fgets(argument, sizeof(argument), stdin);

			k = strlen(argument);
			*(argument + (k - 1)) = '\0';

			printf("(remote-file)\n");
			fgets(argument2, sizeof(argument2), stdin);

			k = strlen(argument2);
			*(argument2 + (k - 1)) = '\0';

			printf("local: %s remote: %s\n", argument, argument2);

		} else if (!strcmp(command, "get")) {
			printf("(remote-file)\n");
			fgets(argument, sizeof(argument), stdin);

			k = strlen(argument);
			*(argument + (k - 1)) = '\0';

			printf("(local-file)\n");
			fgets(argument2, sizeof(argument2), stdin);

			k = strlen(argument2);
			*(argument2 + (k - 1)) = '\0';

			printf("local: %s remote: %s\n", argument2, argument);
		}

		sprintf(getCmd, "%s %s %s", command, argument, argument2);

	}

	if (pasv_mode == PASSIVE) {
		sprintf(sendBuffer, "PASV%s", END_OF_PROTOCOL);
		sendProtocol(sock, sendBuffer);
		state = STATE_S2;
	} else if (pasv_mode == ACTIVE) {
		activeMode();
		state = STATE_S2;
	}

}

void state_S2_reply(char* cmd) {
	char sendBuffer[BUFFER_SIZE];
	char recvBuffer[BUFFER_SIZE];
	char command[BUFFER_SIZE];
	char argument[BUFFER_SIZE];
	char argument2[COMMAND_MAX_SIZE];

	int host0, host1, host2, host3;
	int port0, port1;

	char reply[5];
	memset(reply, 0x00, sizeof(reply));
	memset(command, 0x00, sizeof(command));
	memset(argument, 0x00, sizeof(argument));
	memset(sendBuffer, 0x00, sizeof(sendBuffer));
	memset(recvBuffer, 0x00, sizeof(recvBuffer));
	memset(argument2, 0x00, sizeof(argument2));

	recvProtocol(sock, recvBuffer, BUFFER_SIZE - 1);
	printMessage(recvBuffer);

	sscanf(recvBuffer, "%s ", reply);

	if (!strncmp(reply, "1", 1)) {
		fprintf(stderr, "\nError\n");
		state = STATE_CMD;
		return;
	} else if (!strncmp(reply, "3", 1)) {
		fprintf(stderr, "\nError\n");
		state = STATE_CMD;
		return;
	} else if (!strncmp(reply, "4", 1) || !strncmp(reply, "5", 1)) {
		fprintf(stderr, "\nFailure\n");
		state = STATE_CMD;
		return;
	}

	if (pasv_mode == PASSIVE) {
		sscanf(strchr(recvBuffer, '(') + 1, "%d,%d,%d,%d,%d,%d", &host0, &host1,
				&host2, &host3, &port0, &port1);
		sprintf(serv_ip, "%d.%d.%d.%d", host0, host1, host2, host3);
		serv_port = port0 * 256 + port1;
		//printf("dtp port : %d\n", serv_port);

		printf("IP = %s %d\n", serv_ip,serv_port);
printf("dtpsock = %d\n", dtpSock);
		dtpSock = connectServer(serv_ip, serv_port);
		printf("CONNECT !!!\n");
		printf("dtpsock = %d\n", dtpSock);





	}

	sscanf(cmd, "%s %s %s", command, argument, argument2);

	if (!strcmp(reply, "200")) {
		if (!strcmp(command, "ls")) {
			if (strcmp(argument, "") != 0)
				sprintf(sendBuffer, "LIST %s%s", argument, END_OF_PROTOCOL);
			else
				sprintf(sendBuffer, "LIST%s", END_OF_PROTOCOL);
		} else if (!strcmp(command, "nlist")) {
			if (strcmp(argument, "") != 0)
				sprintf(sendBuffer, "LIST %s%s", argument, END_OF_PROTOCOL);
			else
				sprintf(sendBuffer, "NLST%s", END_OF_PROTOCOL);
		} else if (!strcmp(command, "get")) {
			// request server for transfer start - RETR fileName
			sprintf(sendBuffer, "RETR %s%s", argument, END_OF_PROTOCOL);
		} else if (!strcmp(command, "put")) {

			if (strcmp(argument2, "") != 0) {
				// request server for transfer start - STOR fileName
				sprintf(sendBuffer, "STOR %s%s", argument2, END_OF_PROTOCOL);
			}else{
				// request server for transfer start - STOR fileName
				sprintf(sendBuffer, "STOR %s%s", argument, END_OF_PROTOCOL);
			}
		}
	} else if (!strcmp(reply, "227")) {
		if (!strcmp(command, "ls")) {
			if (strcmp(argument, "") != 0)
				sprintf(sendBuffer, "LIST %s%s", argument, END_OF_PROTOCOL);
			else
				sprintf(sendBuffer, "LIST%s", END_OF_PROTOCOL);
		} else if (!strcmp(command, "nlist")) {
			if (strcmp(argument, "") != 0)
				sprintf(sendBuffer, "LIST %s%s", argument, END_OF_PROTOCOL);
			else
				sprintf(sendBuffer, "NLST%s", END_OF_PROTOCOL);
		} else if (!strcmp(command, "get")) {
			// request server for transfer start - RETR fileName
			sprintf(sendBuffer, "RETR %s%s", argument, END_OF_PROTOCOL);
		} else if (!strcmp(command, "put")) {
			// request server for transfer start - STOR fileName
			sprintf(sendBuffer, "STOR %s%s", argument2, END_OF_PROTOCOL);
		}
	}

	sendProtocol(sock, sendBuffer);
	state = STATE_P;
}

void state_S3_reply() {
	char recvBuffer[BUFFER_SIZE];

	char reply[5];
	memset(reply, 0x00, sizeof(reply));
	memset(recvBuffer, 0x00, sizeof(recvBuffer));

	recvProtocol(sock, recvBuffer, BUFFER_SIZE - 1);
	printMessage(recvBuffer);

	sscanf(recvBuffer, "%s ", reply);
	//printf("reply == %s\n",reply);

	if (!strcmp(reply, "221")) {

		state = STATE_EXIT;

	} else if (!strncmp(reply, "1", 1)) {
		fprintf(stderr, "\nError\n");
		state = STATE_CMD;
	} else if (!strncmp(reply, "3", 1)) {
		fprintf(stderr, "\nError\n");
		state = STATE_CMD;
	} else if (!strncmp(reply, "4", 1) || !strncmp(reply, "5", 1)) {
		fprintf(stderr, "\nFailure\n");
		state = STATE_CMD;
	}
}

void state_I_reply() {
	char sendBuffer[BUFFER_SIZE];
	char recvBuffer[BUFFER_SIZE];
	char cmd[COMMAND_MAX_SIZE];

	char reply[5];
	memset(reply, 0x00, sizeof(reply));
	memset(sendBuffer, 0x00, sizeof(sendBuffer));
	memset(recvBuffer, 0x00, sizeof(recvBuffer));

	recvProtocol(sock, recvBuffer, BUFFER_SIZE - 1);
	printMessage(recvBuffer);

	sscanf(recvBuffer, "%s ", reply);

	if (!strcmp(reply, "220")) {
		state = STATE_CMD;
	} else if (!strcmp(reply, "331")) {
		// send password
		printf("Password: ");
		fgets(cmd, COMMAND_MAX_SIZE, stdin);
		sprintf(sendBuffer, "PASS %s", cmd);

		sendProtocol(sock, sendBuffer);
		state = STATE_S;

	} else if (!strncmp(reply, "1", 1)) {
		fprintf(stderr, "\nError\n");
		state = STATE_CMD;
	} else if (!strncmp(reply, "4", 1) || !strncmp(reply, "5", 1)) {
		fprintf(stderr, "\nFailure\n");
		state = STATE_CMD;
	}
}

void state_P_reply(char* cmd) {
	char sendBuffer[BUFFER_SIZE];
	char recvBuffer[BUFFER_SIZE];
	char command[BUFFER_SIZE];
	char argument[BUFFER_SIZE];
	char reply[5];

	memset(reply, 0x00, sizeof(reply));
	memset(sendBuffer, 0x00, sizeof(sendBuffer));
	memset(recvBuffer, 0x00, sizeof(recvBuffer));
	memset(command, 0x00, sizeof(command));
	memset(argument, 0x00, sizeof(argument));


	recvProtocol(sock, recvBuffer, BUFFER_SIZE - 1);
	printMessage(recvBuffer);

	sscanf(recvBuffer, "%s ", reply);

	sscanf(cmd, "%s %s", command, argument);

	if (!strcmp(reply, "150")) {
		if (!strcmp(command, "get")) {
			// extract fileSize
			sscanf(strchr(recvBuffer, '(') + 1, "%u", &fileSize);
			printf("fileSize: %u\n", fileSize);
		}
		state = STATE_DT;
	} else if (!strncmp(reply, "3", 1)) {
		fprintf(stderr, "\nError\n");
		state = STATE_CMD;

	} else if (!strncmp(reply, "4", 1) || !strncmp(reply, "5", 1)) {
		fprintf(stderr, "\nFailure\n");
		state = STATE_CMD;
	}

}

void state_Data_transfer(char* cmd) {
	char sendBuffer[BUFFER_SIZE];
	char recvBuffer[BUFFER_SIZE * 8];
	char command[BUFFER_SIZE];
	char argument[BUFFER_SIZE];
	char filePath[FILENAME_SIZE];
	char argument2[COMMAND_MAX_SIZE];

	char reply[5];
	memset(reply, 0x00, sizeof(reply));
	memset(command, 0x00, sizeof(command));
	memset(argument, 0x00, sizeof(argument));
	memset(sendBuffer, 0x00, sizeof(sendBuffer));
	memset(recvBuffer, 0x00, sizeof(recvBuffer));
	memset(filePath, 0x00, sizeof(filePath));
	memset(argument2, 0x00, sizeof(argument2));

	sscanf(cmd, "%s %s %s", command, argument, argument2);
	getcwd(filePath, FILENAME_SIZE);

	if (pasv_mode == ACTIVE) {
		dtpSock = accept(listenfd, (SA *) NULL, NULL);
	}

	if (!strcmp(command, "ls")) {
		// recv file list from DTP
		recvProtocol(dtpSock, recvBuffer, BUFFER_SIZE * 8);
		printMessage(recvBuffer);
	} else if (!strcmp(command, "nlist")) {
		// recv file list from DTP
		recvProtocol(dtpSock, recvBuffer, BUFFER_SIZE * 8);
		printMessage(recvBuffer);
	} else if (!strcmp(command, "get")) {
		if (strcmp(argument2, "") != 0) {
			sprintf(filePath, "%s/%s", filePath, argument2);
		} else {
			sprintf(filePath, "%s/%s", filePath, argument);
		}
		// download file from DTP
		// fileSize = downloadFile(dtpSock, filePath, fileSize, hashFlag);
		downloadFile(dtpSock, filePath, fileSize, hashFlag);

	} else if (!strcmp(command, "put")) {
		sprintf(filePath, "%s/%s", filePath, argument);

		// file upload to DTP
		uploadFile(dtpSock, filePath, hashFlag); // think about file not exist in filesystem
		//fileSize = uploadFile(dtpSock, filePath, hashFlag); // think about file not exist in filesystem
		close(dtpSock);
	}

	// recv complete message from PI server
	memset(recvBuffer, 0x00, sizeof(recvBuffer));
	recvProtocol(sock, recvBuffer, BUFFER_SIZE - 1);
	printMessage(recvBuffer);

	sscanf(recvBuffer, "%s ", reply);

	if (!strcmp(reply, "226")) {
		if (strcmp(command, "put")!=0) {
			close(dtpSock);
		}
		state = STATE_CMD;
	} else if (!strncmp(reply, "1", 1)) {
		fprintf(stderr, "\nError\n");
		state = STATE_CMD;
	} else if (!strncmp(reply, "3", 1)) {
		fprintf(stderr, "\nError\n");
		state = STATE_CMD;
	} else if (!strncmp(reply, "4", 1) || !strncmp(reply, "5", 1)) {
		fprintf(stderr, "\nFailure\n");
		state = STATE_CMD;
	}
}

// map command to handler 
void commandHandle(char *cmd) {
	int i;
	int p=0;
	int numCmd = sizeof(ftpCmdHandler) / sizeof(FtpCmdHandler);

	for (i = 0; i < numCmd; i++) {
		if (!strncmp(cmd, ftpCmdHandler[i].cmd, strlen(ftpCmdHandler[i].cmd))) {
			p=1;
			(*(ftpCmdHandler[i].handler))(cmd);
			break;
		}
	}
	if(p==0)
		printf("?Invalid command\n");

}

void defaultHandler(char *cmd) {
	printf("default handler: %s\n", cmd);
}

// ftp server connect 
void openCon(char *openCmd) {
	char serverIp[16];
	int k;

	memset(serverIp, 0x00, sizeof(serverIp));

	//initializeFtpClient();

	if (!strcmp(openCmd, "open")) {
		printf("(to)\n");
		fgets(serverIp, sizeof(serverIp), stdin);

		k = strlen(serverIp);
		*(serverIp + (k - 1)) = '\0';

	} else {
		sscanf(openCmd, "%*s %s%*c", serverIp);
	}

// connect to server
	sock = connectServer(serverIp, FTP_PORT);
	if(sock!=-1)
		state = STATE_I;
}

void userLog(char *userlogCmd) {
	char user_id[BUFFER_SIZE];
	char sendBuffer[BUFFER_SIZE];
	memset(user_id, 0x00, BUFFER_SIZE);
	int k;

	if (!strcmp(userlogCmd, "user")) {

		printf("(username) ");

		fgets(user_id, COMMAND_MAX_SIZE, stdin);

		k = strlen(user_id);
		*(user_id + (k - 1)) = '\0';

		sprintf(sendBuffer, "User %s%s", user_id, END_OF_PROTOCOL);

		sendProtocol(sock, sendBuffer);

	} else {
		sscanf(userlogCmd, "%*s %s", user_id);

		sprintf(sendBuffer, "User %s%s", user_id, END_OF_PROTOCOL);

		sendProtocol(sock, sendBuffer);
	}
	state = STATE_I;
}

// send EPSV or PASS to Server
void passiveMode(char *ip, int *port) {
	char sendBuffer[BUFFER_SIZE];
	char recvBuffer[BUFFER_SIZE];
	int host0, host1, host2, host3;
	int port0, port1;

	sprintf(sendBuffer, "PASV%s", END_OF_PROTOCOL);

	sendProtocol(sock, sendBuffer);
	recvProtocol(sock, recvBuffer, BUFFER_SIZE - 1);
	printMessage(recvBuffer);

	sscanf(strchr(recvBuffer, '(') + 1, "%d,%d,%d,%d,%d,%d", &host0, &host1,
			&host2, &host3, &port0, &port1);
	sprintf(ip, "%d.%d.%d.%d", host0, host1, host2, host3);

	*port = port0 * 256 + port1;

	printf("dtp port : %d\n", *port);
}

void activeMode() { //char* activeCmd) { //char *ip, int *port) {
	char sendBuffer[BUFFER_SIZE];
	int host0, host1, host2, host3;
	int port0, port1;

	int len;

	len = sizeof cliaddr;
	getsockname(sock, (struct sockaddr *) &cliaddr, &len);
	//printf("sockaddr:%s\n",inet_ntoa(cliaddr.sin_addr));



	//printf("port: %d\n", ntohs(servaddr.sin_port));
	//printf("port0: %d////port1: %d\n", port0, port1);
	sscanf(inet_ntoa(cliaddr.sin_addr), "%d.%d.%d.%d", &host0, &host1, &host2,
			&host3);

	if (listenfd == -1) {
		 srand((unsigned int) time(NULL));
		 do {
		  port = random() % 64512 + 1024; ////1024~65536
		 } while (port == servaddr.sin_port);

		listenfd = Socket(AF_INET, SOCK_STREAM, 0);
		bzero(&cliaddr, sizeof(cliaddr));
		cliaddr.sin_family = AF_INET;
		cliaddr.sin_addr.s_addr = htonl(INADDR_ANY);
		cliaddr.sin_port = htons(port);
		Bind(listenfd, (SA *) &cliaddr, sizeof(cliaddr));
		Listen(listenfd, LISTENQ);
	}

	port1 = port % 256;
	port0 = port / 256;

	sprintf(sendBuffer, "PORT %d,%d,%d,%d,%d,%d%s", host0, host1, host2, host3,
			port0, port1, END_OF_PROTOCOL);

	sendProtocol(sock, sendBuffer);
}

void list(char *listCmd) {
	char sendBuffer[BUFFER_SIZE];

	memset(sendBuffer, 0x00, sizeof(sendBuffer));
	if (check_connection == 0) {
		printf("Not connected.\n");
		return;
	}
	if (type == TYPE_I) {
		ascii(0);
		state = STATE_S1;
		return;
	} else {
		if (pasv_mode == PASSIVE) {
			sprintf(sendBuffer, "PASV%s", END_OF_PROTOCOL);

			sendProtocol(sock, sendBuffer);
			state = STATE_S2;
		} else if (pasv_mode == ACTIVE) {
			activeMode();
			state = STATE_S2;
		}
	}
	return;
}

// get remote working directory file list
void nlist(char *nlistCmd) {
	list(0);
}

// file upload
/*
 void put(char *putCmd) {
 //int listenfd;
 int port;
 char ip[16], filePath[FILENAME_SIZE], fileName[50];
 char sendBuffer[BUFFER_SIZE];
 char recvBuffer[BUFFER_SIZE];

 sscanf(putCmd, "%*s %s%*c", fileName);

 // get local current working directory
 getcwd(filePath, FILENAME_SIZE);
 sscanf(putCmd, "%*s %s%*c", fileName);
 sprintf(filePath, "%s/%s", filePath, fileName);

 debug("put");
 debug(filePath);



 if (pasv_mode == PASSIVE) {
 sprintf(sendBuffer, "PASV%s", END_OF_PROTOCOL);
 sendProtocol(sock, sendBuffer);
 state = STATE_S2;
 } else if (pasv_mode == ACTIVE) {
 activeMode();
 state = STATE_S2;
 }

 ////////////////////////////////////////
 ///////////////////////////////////////////////////
 //////////////////////////////////////////////////////

 }
 */
// change remote working directory
void cd(char *cdCmd) {
	if (check_connection == 0) {
		printf("Not connected.\n");
		return;
	}
	char sendBuffer[BUFFER_SIZE];
	char recvBuffer[BUFFER_SIZE];

	sscanf(cdCmd, "%*s %s%*c", recvBuffer);

	sprintf(sendBuffer, "CWD %s%s", recvBuffer, END_OF_PROTOCOL);

	sendProtocol(sock, sendBuffer);

	state = STATE_S;
	/*
	 recvProtocol(sock, recvBuffer, BUFFER_SIZE);
	 printMessage(recvBuffer);
	 */
}

void close_(char *closeCmd) {
	char sendBuffer[BUFFER_SIZE];

	if (check_connection == 0) {
		printf("Not connected.\n");
		return;
	}

	sprintf(sendBuffer, "QUIT%s", END_OF_PROTOCOL);

	sendProtocol(sock, sendBuffer);

	state = STATE_S;

}

// ftp client exit 
void quit(char *quitCmd) {
	char sendBuffer[BUFFER_SIZE];

	if (check_connection == 1) {
		sprintf(sendBuffer, "QUIT%s", END_OF_PROTOCOL);

		sendProtocol(sock, sendBuffer);

		state = STATE_S3;
		return;
	} else {
		state = STATE_EXIT;
	}

}

// get remote working directory
void pwd(char *pwdCmd) {
	char sendBuffer[BUFFER_SIZE];
	if (check_connection == 0) {
		printf("Not connected.\n");
		return;
	}
	sprintf(sendBuffer, "PWD%s", END_OF_PROTOCOL);
	sendProtocol(sock, sendBuffer);
	state = STATE_S;
}

// hash option on/off
void hash(char *hashCmd) {
	hashFlag = !hashFlag;

	if (hashFlag == 0) {
		printMessage("hash off\n");
	} else {
		printMessage("hash on\n");
	}
}

// shell command - not implemented
void shellEscape(char *shellCmd) {
	printMessage("not implemented");
}

void printMessage(char *msg) {
	printf("%s", msg);
}

void syst(char *systCmd) {
	char sendBuffer[BUFFER_SIZE];
	if (check_connection == 0) {
		printf("Not connected.\n");
		return;
	}

	sprintf(sendBuffer, "SYST%s", END_OF_PROTOCOL);

	sendProtocol(sock, sendBuffer);

	state = STATE_S;

}

void ascii(char *asciiCmd) {
	char sendBuffer[BUFFER_SIZE];
	if (check_connection == 0) {
		printf("Not connected.\n");
		return;
	}

	sprintf(sendBuffer, "TYPE A%s", END_OF_PROTOCOL);
	sendProtocol(sock, sendBuffer);

	type = TYPE_A;
	state = STATE_S;
}
void binary(char *binaryCmd) {
	char sendBuffer[BUFFER_SIZE];
	if (check_connection == 0) {
		printf("Not connected.\n");
		return;
	}

	sprintf(sendBuffer, "TYPE I%s", END_OF_PROTOCOL);
	sendProtocol(sock, sendBuffer);

	type = TYPE_I;
	state = STATE_S;
}

void debugOn(char *msg) {
	if (debug_mode == 0) {
		debug_mode = MODE_DEBUG;
		printf("Debugging ON (debug =1)\n");
	} else {
		debug_mode = 0;
		printf("Debugging OFF (debug =0)\n");
	}
}

void passiveOn(char *msg) {
	if (pasv_mode == ACTIVE) {
		pasv_mode = PASSIVE;
		printf("Passive mode ON\n");
		if (listenfd != -1) {
			close(listenfd);
			printf("listenfd==[%d]\n", listenfd);
			listenfd = -1;

			printf("listenfd==[%d]\n", listenfd);
		}

	} else {
		pasv_mode = ACTIVE;

		printf("Passive mode OFF\n");

	}
}

void checkType(char *typeCmd) {

	if (check_connection == 0) {
		printf("Not connected.\n");
		return;
	}
	if (type == TYPE_A) {
		printf("Using ascii mode to transfer files\n");
	} else if (type == TYPE_I) {
		printf("Using binary mode to transfer files\n");
	}
}

void lcd(char *lcdCmd) {
	DIR *dp;

	int n = 0;
	char folder[BUFFER_SIZE];
	char nowdir[BUFFER_SIZE];
	char tmp[BUFFER_SIZE];
	int k;
	/*
	 k = strlen(lcdCmd);
	 *(lcdCmd + (k - 1)) = '\0';
	 */
	n = sscanf(lcdCmd, "%*s %s %s", folder, tmp);

	getcwd(nowdir, BUFFER_SIZE);
	if (n == 1) {
		if ((dp = opendir(folder)) == NULL) {
			fprintf(stderr, "\nlocal : %s: No such file or directory\n", folder);
			return;
		}

		sprintf(nowdir, "%s/%s", nowdir, folder);
		chdir(nowdir);
		getcwd(nowdir, BUFFER_SIZE);
		closedir(dp);
	} else if (n > 1) {
		fprintf(stderr, "\nusage : lcd local-directory\n");
	}

	printf("Local directory now %s\n", nowdir);

	return;

}

/*
int connectServer(char *serverIp, short port) {
	int sock;
	struct sockaddr_in servAddr;

	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		perror("sock failed");
		exit(1);
	}

	memset(&servAddr, 0, sizeof(servAddr));
	servAddr.sin_family = AF_INET;
	servAddr.sin_addr.s_addr = inet_addr(serverIp);
	servAddr.sin_port = htons(port);

	if (connect(sock, (struct sockaddr*)&servAddr, sizeof(servAddr)) == -1) {
		perror("connect failed");
		exit(1);
	}

	return sock;
}
*/

int connectServer(char *serverIp, short port) {
	int sock;

	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		perror("sock failed");
		exit(1);
	}

	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = inet_addr(serverIp);
	servaddr.sin_port = htons(port);

	if (connect(sock, (struct sockaddr*) &servaddr, sizeof(servaddr)) == -1) {
		//sock=-1;
		perror("connect: ");
	}

	return sock;
}
